﻿using System;
using System.Runtime.InteropServices;
using Koonsoft.HYCRM.DAL;
using log4net;

/* =============================================================================
 * Function   : ET_CheckPwdz201
 * Description: OTP Z201(TOTP) 认证接口
 * Parameter  : 
 *		authkey			令牌密钥
 *      t               当前时间相对UTC Epoch秒数
 *      t0              起始参考时间相对UTC Epoch秒数(默认为0)
 *      x               TOTP变化周期(默认为60秒)
 *      drift           漂移次数
 *      authwnd		    认证范围, 通常是0-20
 *      lastsucc        前一次认证成功的相对UTC Epoch秒数(为防止重放攻击)
 *      otp				需要认证的动态口令
 *      otplen			需要认证的动态口令长度, 通常是6
 *      currsucc		认证成功后的相对UTC Epoch秒数
 *      currdft         认证成功后的当前漂移次数
 *
 * return     : 0 - 成功, 其他值为错误.
 *
 *int __stdcall ET_CheckPwdz201(char *authkey, uint64_t t, uint64_t t0, 
 *   unsigned int x, int drift, int authwnd, uint64_t lastsucc, 
 *   const char *otp, int otplen, uint64_t *currsucc, int *currdft);
 */

/* =============================================================================
 * Function   : ET_Syncz201
 * Description: OTP Z201(TOTP) 同步接口
 * Parameter  : 
 *		authkey			令牌密钥，已经加密过的，需要对其进行解密
 *      t               当前时间相对UTC Epoch秒数
 *      t0              起始参考时间相对UTC Epoch秒数(默认为0)
 *      x               TOTP变化周期(默认为60秒)
 *      drift           漂移次数
 *      syncwnd         同步范围, 通常是0-20
 *      lastsucc        前一次认证成功的相对UTC Epoch秒数(为防止重放攻击)
 *      otp1            需要同步的第一个动态口令
 *      otp1len			需要同步的第一个动态口令长度, 通常是6
 *      otp2            需要同步的第二个动态口令
 *      otp2len         需要同步的第二个动态口令长度, 通常是6
 *      currsucc		认证成功后的相对UTC Epoch秒数
 *      currdft         认证成功后的当前漂移次数
 *
 * return     : 0 - 成功, 其他值为错误.
 
 *int __stdcall ET_Syncz201(char *authkey, uint64_t t, uint64_t t0, 
 *      unsigned int x, int drift, int syncwnd, uint64_t lastsucc, 
 *      const char *otp1, int otp1len, const char *otp2, int otp2len, 
 *      uint64_t *currsucc, int *currdft);
 */

namespace Koonsoft.HYCRM.BLL
{
    public class OTPHelper
    {
        private static ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        [DllImport("ET_OTPVerify.dll")]
        public static extern int ET_CheckPwdz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int authwnd, UInt64 lastsucc, string otp, int otplen, ref UInt64 currsucc, ref int currdft);


        [DllImport("ET_OTPVerify.dll")]
        public static extern int ET_Syncz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int syncwnd, UInt64 lastsucc, string otp1, int otp1len, string otp2, int otp2len, ref UInt64 currsucc, ref int currdft);

        static UInt64 currsucc1 = 0;
        static int currdft1 = 0;

        /// <summary>
        /// 验证动态密保
        /// </summary>
        /// <param name="otpCode"></param>
        /// <param name="barcode"></param>
        /// <returns></returns>
        public static bool Verify(string otpCode, string barcode)
        {
            int iRe = 0;

            try
            {

                var authkey = OTPDAL.GetOTPInfoByBarcode(barcode).Authkey;

                UInt64 currsucc = OTPDAL.GetOTPInfoByBarcode(barcode).Currsucc;
                int currdft = OTPDAL.GetOTPInfoByBarcode(barcode).Currdft;

                TimeSpan tsTimeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1);
                ulong ulgTimeStamp = (ulong)tsTimeSpan.TotalSeconds;

                iRe = ET_CheckPwdz201(authkey, ulgTimeStamp, 0, 60, currdft1, 40, currsucc1, otpCode, 6, ref currsucc, ref currdft);
                if (iRe == 0)
                {

                    // update database
                    //currsucc1 = currsucc;
                    //currdft1 = currdft;
                    OTPDAL.UpdateOTPInfo(currsucc, currdft, barcode);

                    return true;
                }

            }
            catch (Exception ex)
            {
                logger.Error("验证动态码失败", ex);
            }

            return false;
        }
    }
}
